package com.github.itdachen.quartz.service.impl;

import com.github.itdachen.framework.context.exception.BizException;
import com.github.itdachen.quartz.entity.CronJobInfo;
import com.github.itdachen.quartz.entity.CronJobResp;
import com.github.itdachen.quartz.service.IQuartzJobService;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 任务实现
 *
 * @author 剑鸣秋朔
 * @date 2025/11/21 21:44
 */
@Service
public class QuartzJobServiceImpl implements IQuartzJobService {
    private static final Logger logger = LoggerFactory.getLogger(QuartzJobServiceImpl.class);

    private final SchedulerFactoryBean schedulerFactoryBean;

    public QuartzJobServiceImpl(SchedulerFactoryBean schedulerFactoryBean) {
        this.schedulerFactoryBean = schedulerFactoryBean;
    }

    /***
     * 查询
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:52
     * @return java.util.List<com.github.itdachen.topic.quartz.entity.CronJobResp>
     */
    @Override
    public List<CronJobResp> query() throws Exception {
        List<CronJobResp> cronJobDtoList = new ArrayList();

        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            CronJobResp cronJobResp = new CronJobResp();
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    cronJobResp = new CronJobResp();
                    cronJobResp.setName(jobKey.getName());
                    cronJobResp.setGroup(jobKey.getGroup());

                    //get job's trigger
                    List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                    CronTrigger cronTrigger = (CronTrigger) triggers.get(0);
                    cronJobResp.setNextFireTime(cronTrigger.getNextFireTime());
                    cronJobResp.setPreFireTime(cronTrigger.getPreviousFireTime());
                    cronJobResp.setCronExpression(cronTrigger.getCronExpression());
                    cronJobResp.setDescription(cronTrigger.getDescription());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(cronTrigger.getKey());
                    cronJobResp.setState(triggerState.name());

                    cronJobDtoList.add(cronJobResp);
                }

            }
        } catch (SchedulerException e) {
            logger.error("查看定时任务失败: " + e);
            throw new BizException("查看定时任务失败: 调度异常");
        }
        logger.info("查看定时任务结束：{}", cronJobDtoList);

        return cronJobDtoList;
    }

    /***
     * 手动执行
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:47
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void run(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        logger.info("手动执行任务开始：{}, {}", jobClassName, jobGroupName);
        // triggerJob 手动触发
        schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    /***
     * 新增任务
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:48
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void save(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        String cronExpression = cronJobInfo.getCronExpression();
        String description = cronJobInfo.getDescription();
        logger.info("创建定时任务开始：{}，{}，{}，{}", jobClassName, jobGroupName, cronExpression, description);

        // =================== 重点 ===================
        try {
            // 通过SchedulerFactory获取一个调度器实例
            Scheduler sched = schedulerFactoryBean.getScheduler();

            // 启动调度器
            sched.start();

            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobClassName)).withIdentity(jobClassName, jobGroupName).build();

            //表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName).withDescription(description).withSchedule(scheduleBuilder).build();

            sched.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            logger.error("创建定时任务失败: " + e);
            throw new BizException("创建定时任务失败：调度异常");
        } catch (ClassNotFoundException e) {
            logger.error("创建定时任务失败: " + e);
            throw new BizException("创建定时任务失败：任务类不存在");
        }
        logger.info("创建定时任务结束 ...");
    }

    /***
     * 重置、修改
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:50
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void reschedule(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        String cronExpression = cronJobInfo.getCronExpression();
        String description = cronJobInfo.getDescription();
        logger.info("更新定时任务开始：{}，{}，{}，{}", jobClassName, jobGroupName, cronExpression, description);

        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTriggerImpl trigger1 = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
            trigger1.setStartTime(new Date()); // 重新设置开始时间
            CronTrigger trigger = trigger1;

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withDescription(description).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (Exception e) {
            logger.error("更新定时任务失败:" + e);
            throw new BizException("更新定时任务失败：调度异常");
        }
        logger.info("更新定时任务结束：...");
    }

    /***
     * 暂停任务
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:49
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void pause(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        logger.info("暂停定时任务开始：{}，{}", jobClassName, jobGroupName);

        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            logger.error("暂停定时任务失败:" + e);
            throw new BizException("暂停定时任务失败：调度异常");
        }
        logger.info("暂停定时任务结束：...");
    }

    /***
     * 重启任务
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:50
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void resume(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        logger.info("重启定时任务开始：{}，{}", jobClassName, jobGroupName);

        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            logger.error("重启定时任务失败:" + e);
            throw new BizException("重启定时任务失败：调度异常");
        }
        logger.info("重启定时任务结束...");
    }

    /***
     * 删除任务
     *
     * @author 剑鸣秋朔
     * @date 2025/11/21 21:51
     * @param cronJobInfo cronJobInfo
     * @return void
     */
    @Override
    public void delete(CronJobInfo cronJobInfo) throws Exception {
        String jobClassName = cronJobInfo.getClassName();
        String jobGroupName = cronJobInfo.getGroupName();
        logger.info("删除定时任务开始：{}，{}", jobClassName, jobGroupName);
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            logger.error("删除定时任务失败:" + e);
            throw new BizException("删除定时任务失败：调度异常");
        }
        logger.info("删除定时任务结束...");
    }
}
